package com.lry.basic.proxy.demo1;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * @author:刘仁有
 * @desc:
 * @email:953506233@qq.com
 * @data:2019/12/23
 */
public class ProxyUtils {
    public static Object newInstance(Class clazz, CustomInvocationHandler h){
        Object proxy = null;
        Method methods[] = clazz.getDeclaredMethods();

        String line = "\n";
        String tab = "\t";
        String content = "";
        String packageContent = "package com.google;"+line;
        String importContent = "import "+clazz.getName()+";"+line+
                                "import com.lry.basic.proxy.demo1.CustomInvocationHandler;"+line+
                                "import java.lang.Exception;"+line+
                                "import java.lang.reflect.Method;"+line;

        String clazzFirstLineContent = "public class $Proxy implements "+clazz.getSimpleName()+"{"+line;

        String filedContent  =tab+"private CustomInvocationHandler h;"+line;
        String constructorContent =tab+"public $Proxy (CustomInvocationHandler h){" +line
                +tab+tab+"this.h =h;"
                +line+tab+"}"+line;

        String methodContent = "";
        for (Method method:methods) {
            String returnTypeName = method.getReturnType().getSimpleName();
            String methodName = method.getName();

            Class args[] = method.getParameterTypes();
            String argsContent = "";
            String paramsContent = "";
            String classContent = "";
            int flag = 0;
            for (Class arg:args) {
                String tmp = arg.getSimpleName();
                argsContent+=tmp+" p"+flag+",";
                paramsContent+=",p"+flag;
                classContent+=","+arg.getSimpleName()+".class";
                flag++;
            }
            if(argsContent.length()>0){
                argsContent = argsContent.substring(0,argsContent.lastIndexOf(","));
            }
            methodContent+=tab+"public "+returnTypeName+" "+methodName+"("+argsContent+")throws Exception{"+line
            +tab+tab+"Method method = Class.forName(\""+clazz.getName()+"\").getDeclaredMethod(\""+methodName+"\""+classContent+");"+line+
            tab+tab+"return ("+returnTypeName+")h.invoke(method"+paramsContent+");"+line+
            tab+"}"+line;
        }
        content = packageContent+importContent+clazzFirstLineContent+filedContent+constructorContent+methodContent+"}";

        File file =new File("d:\\com\\google\\$Proxy.java");
        try {
            if(!file.exists()){
                file.createNewFile();
            }
            FileWriter fw = new FileWriter(file);
            fw.write(content);
            fw.flush();
            fw.close();

            //编译
            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
            StandardJavaFileManager fileManager = compiler.getStandardFileManager(null,null,null);
            Iterable units = fileManager.getJavaFileObjects(file);
            JavaCompiler.CompilationTask t = compiler.getTask(null, fileManager, null, null, null, units);
            t.call();
            fileManager.close();

            URL[]urls = new URL[]{new URL("file:D:\\\\")};
            URLClassLoader loader = new URLClassLoader(urls);
            Class loaderClass = loader.loadClass("com.google.$Proxy");
            Constructor con = loaderClass.getConstructor(CustomInvocationHandler.class);
            proxy = con.newInstance(h);
        }catch (Exception e){
            e.printStackTrace();
        }
        return  proxy;
    }
}
